home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch17 / Plane.cls < prev    next >
Text File  |  1999-07-06  |  15KB  |  501 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "RayPlane"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16. ' A plane object.
  17.  
  18. Implements RayTraceable
  19.  
  20. Private Point1 As Point3D   ' Point on plane.
  21. Private Point2 As Point3D   ' Normal = P2 - P1.
  22.  
  23. ' Wire frame variables.
  24. Private Const WIRE_MAX = 3
  25. Private Const WIRE_DX = 50
  26. Private WireFrame(-WIRE_MAX To WIRE_MAX, -WIRE_MAX To WIRE_MAX) As Point3D
  27.  
  28. ' Ambient light parameters.
  29. Private AmbientKr As Single
  30. Private AmbientKg As Single
  31. Private AmbientKb As Single
  32.  
  33. ' Diffuse light parameters.
  34. Private DiffuseKr As Single
  35. Private DiffuseKg As Single
  36. Private DiffuseKb As Single
  37.  
  38. ' Specular reflection parameters.
  39. Private SpecularN As Single
  40. Private SpecularK As Single
  41.  
  42. ' Reflected light parameters.
  43. Private ReflectedKr As Single
  44. Private ReflectedKg As Single
  45. Private ReflectedKb As Single
  46.  
  47. ' Refracted light parameters.
  48. Private TransN As Single
  49. Private n1 As Single   ' Index of refraction outside the object.
  50. Private n2 As Single   ' Index of refraction inside the object.
  51. Private TransmittedKr As Single
  52. Private TransmittedKg As Single
  53. Private TransmittedKb As Single
  54.  
  55. Private IsReflective As Boolean
  56. Private IsTransparent As Boolean
  57. Private DoneOnThisScanline As Boolean
  58.  
  59. ' We had a hit on this scanline.
  60. Private HadHit As Boolean
  61.  
  62. ' We have had a hit on a previous scanline.
  63. Private HadHitOnPreviousScanline As Boolean
  64.  
  65. ' We will not be visible on later scanlines.
  66. Private ForeverCulled As Boolean
  67.  
  68. ' Return an appropriate color for this object.
  69. Private Function GetColor() As Long
  70. Dim R As Integer
  71. Dim G As Integer
  72. Dim B As Integer
  73.  
  74.     R = 255 * (DiffuseKr + AmbientKr): If R > 255 Then R = 255
  75.     G = 255 * (DiffuseKg + AmbientKg): If G > 255 Then G = 255
  76.     B = 255 * (DiffuseKb + AmbientKb): If B > 255 Then B = 255
  77.     GetColor = RGB(R, G, B)
  78. End Function
  79. ' Return the right shade for this polygon.
  80. Private Function GetShade(ByVal pgon As SimplePolygon) As Long
  81. Dim i As Integer
  82. Dim px As Single
  83. Dim py As Single
  84. Dim pz As Single
  85. Dim light_source As LightSource
  86. Dim total_r As Single
  87. Dim total_g As Single
  88. Dim total_b As Single
  89. Dim R1 As Integer
  90. Dim g1 As Integer
  91. Dim b1 As Integer
  92. Dim empty_objects As Collection
  93.  
  94.     With pgon
  95.         ' Find a central point on this polygon.
  96.         For i = 1 To .PointX.Count
  97.             px = px + .PointX(i)
  98.             py = py + .PointY(i)
  99.             pz = pz + .PointZ(i)
  100.         Next i
  101.         px = px / .PointX.Count
  102.         py = py / .PointX.Count
  103.         pz = pz / .PointX.Count
  104.  
  105.         ' Add up the light components.
  106.         Set empty_objects = New Collection
  107.         For Each light_source In LightSources
  108.             CalculateHitColorDSA _
  109.                 1, empty_objects, Nothing, _
  110.                 EyeX, EyeY, EyeZ, _
  111.                 px, py, pz, .Nx, .Ny, .Nz, _
  112.                 DiffuseKr, DiffuseKg, DiffuseKb, AmbientKr, AmbientKg, AmbientKb, _
  113.                 SpecularK, SpecularN, R1, g1, b1
  114.             total_r = total_r + R1
  115.             total_g = total_g + g1
  116.             total_b = total_b + b1
  117.         Next light_source
  118.     End With
  119.  
  120.     If total_r > 255 Then total_r = 255
  121.     If total_g > 255 Then total_g = 255
  122.     If total_b > 255 Then total_b = 255
  123.  
  124.     GetShade = RGB(total_r, total_g, total_b)
  125. End Function
  126.  
  127. ' Return the unit surface normal.
  128. Private Sub GetUnitNormal(ByRef Nx As Single, ByRef Ny As Single, ByRef Nz As Single)
  129. Dim n_len As Single
  130.  
  131.     Nx = Point2.Trans(1) - Point1.Trans(1)
  132.     Ny = Point2.Trans(2) - Point1.Trans(2)
  133.     Nz = Point2.Trans(3) - Point1.Trans(3)
  134.     n_len = Sqr(Nx * Nx + Ny * Ny + Nz * Nz)
  135.     Nx = Nx / n_len
  136.     Ny = Ny / n_len
  137.     Nz = Nz / n_len
  138. End Sub
  139.  
  140. ' Add non-backface polygons to this collection.
  141. Public Sub RayTraceable_GetPolygons(ByRef num_polygons As Integer, polygons() As SimplePolygon, ByVal shaded As Boolean)
  142. Dim i As Integer
  143. Dim j As Integer
  144. Dim pgon As SimplePolygon
  145. Dim color As Long
  146.  
  147.     ' If all polygons are the same color,
  148.     ' get an appropriate color.
  149.     If Not shaded Then
  150.         color = GetColor()
  151.     End If
  152.  
  153.     For i = -WIRE_MAX To WIRE_MAX - 1
  154.         For j = -WIRE_MAX To WIRE_MAX - 1
  155.             ' Make a polygon.
  156.             Set pgon = New SimplePolygon
  157.             With WireFrame(i, j)
  158.                 pgon.AddPoint .Trans(1), .Trans(2), .Trans(3)
  159.             End With
  160.             With WireFrame(i, j + 1)
  161.                 pgon.AddPoint .Trans(1), .Trans(2), .Trans(3)
  162.             End With
  163.             With WireFrame(i + 1, j + 1)
  164.                 pgon.AddPoint .Trans(1), .Trans(2), .Trans(3)
  165.             End With
  166.             With WireFrame(i + 1, j)
  167.                 pgon.AddPoint .Trans(1), .Trans(2), .Trans(3)
  168.             End With
  169.             pgon.Finish
  170.  
  171.             ' Add it to the list.
  172.             With pgon
  173.                 ' See if we are shaded.
  174.                 If shaded Then
  175.                     ' We are shaded. Get the
  176.                     ' right color.
  177.                     .ForeColor = GetShade(pgon)
  178.                     .FillColor = .ForeColor
  179.                 Else
  180.                     ' We are not shaded. Use the
  181.                     ' normal colors.
  182.                     .ForeColor = vbBlack
  183.                     .FillColor = color
  184.                 End If
  185.                 num_polygons = num_polygons + 1
  186.                 ReDim Preserve polygons(1 To num_polygons)
  187.                 Set polygons(num_polygons) = pgon
  188.             End With
  189.         Next j
  190.     Next i
  191. End Sub
  192. ' Draw a wireframe for this object.
  193. Public Sub RayTraceable_DrawWireFrame(ByVal pic As PictureBox)
  194. Dim i As Integer
  195. Dim j As Integer
  196.  
  197.     ' Use an appropriate color.
  198.     pic.ForeColor = GetColor()
  199.  
  200.     ' Draw i lines.
  201.     For i = -WIRE_MAX To WIRE_MAX
  202.         With WireFrame(i, -WIRE_MAX)
  203.             pic.CurrentX = .Trans(1)
  204.             pic.CurrentY = .Trans(2)
  205.         End With
  206.  
  207.         For j = -WIRE_MAX + 1 To WIRE_MAX
  208.             With WireFrame(i, j)
  209.                 pic.Line -(.Trans(1), .Trans(2))
  210.             End With
  211.         Next j
  212.     Next i
  213.  
  214.     ' Draw j lines.
  215.     For j = -WIRE_MAX To WIRE_MAX
  216.         With WireFrame(-WIRE_MAX, j)
  217.             pic.CurrentX = .Trans(1)
  218.             pic.CurrentY = .Trans(2)
  219.         End With
  220.  
  221.         For i = -WIRE_MAX + 1 To WIRE_MAX
  222.             With WireFrame(i, j)
  223.                 pic.Line -(.Trans(1), .Trans(2))
  224.             End With
  225.         Next i
  226.     Next j
  227. End Sub
  228.  
  229. ' Initialize the object using text parameters in
  230. ' a comma-delimited list.
  231. Public Sub SetParameters(ByVal txt As String)
  232.     On Error GoTo PlaneParamError
  233.  
  234.     ' Read the parameters and initialize the object.
  235.     ' Geometry.
  236.     Point1.Coord(1) = CSng(GetDelimitedToken(txt, ","))
  237.     Point1.Coord(2) = CSng(GetDelimitedToken(txt, ","))
  238.     Point1.Coord(3) = CSng(GetDelimitedToken(txt, ","))
  239.     Point1.Coord(4) = 1
  240.     Point2.Coord(1) = Point1.Coord(1) + CSng(GetDelimitedToken(txt, ","))
  241.     Point2.Coord(2) = Point1.Coord(2) + CSng(GetDelimitedToken(txt, ","))
  242.     Point2.Coord(3) = Point1.Coord(3) + CSng(GetDelimitedToken(txt, ","))
  243.     Point2.Coord(4) = 1
  244.  
  245.     ' Ambient light.
  246.     AmbientKr = CSng(GetDelimitedToken(txt, ","))
  247.     AmbientKg = CSng(GetDelimitedToken(txt, ","))
  248.     AmbientKb = CSng(GetDelimitedToken(txt, ","))
  249.  
  250.     ' Diffuse reflection.
  251.     DiffuseKr = CSng(GetDelimitedToken(txt, ","))
  252.     DiffuseKg = CSng(GetDelimitedToken(txt, ","))
  253.     DiffuseKb = CSng(GetDelimitedToken(txt, ","))
  254.  
  255.     ' Specular reflection.
  256.     SpecularN = CSng(GetDelimitedToken(txt, ","))
  257.     SpecularK = CSng(GetDelimitedToken(txt, ","))
  258.  
  259.     ' Reflected light.
  260.     ReflectedKr = CSng(GetDelimitedToken(txt, ","))
  261.     ReflectedKg = CSng(GetDelimitedToken(txt, ","))
  262.     ReflectedKb = CSng(GetDelimitedToken(txt, ","))
  263.     IsReflective = (ReflectedKr > 0) Or (ReflectedKg > 0) Or (ReflectedKb > 0)
  264.  
  265.     ' Transmitted light.
  266.     TransN = CSng(GetDelimitedToken(txt, ","))
  267.     n1 = CSng(GetDelimitedToken(txt, ","))
  268.     n2 = CSng(GetDelimitedToken(txt, ","))
  269.     TransmittedKr = CSng(GetDelimitedToken(txt, ","))
  270.     TransmittedKg = CSng(GetDelimitedToken(txt, ","))
  271.     TransmittedKb = CSng(GetDelimitedToken(txt, ","))
  272.     IsTransparent = (TransmittedKr > 0) Or (TransmittedKg > 0) Or (TransmittedKb > 0)
  273.  
  274.     ' Make a wire frame.
  275.     MakeWireFrame
  276.  
  277.     Exit Sub
  278.  
  279. PlaneParamError:
  280.     MsgBox "Error initializing plane parameters."
  281. End Sub
  282.  
  283. ' Make a wire frame.
  284. Private Sub MakeWireFrame()
  285. Dim i As Integer
  286. Dim j As Integer
  287. Dim X As Single
  288. Dim Y As Single
  289. Dim Z As Single
  290. Dim Nx As Single
  291. Dim Ny As Single
  292. Dim Nz As Single
  293. Dim v1x As Single
  294. Dim v1y As Single
  295. Dim v1z As Single
  296. Dim v2x As Single
  297. Dim v2y As Single
  298. Dim v2z As Single
  299. Dim length As Single
  300.  
  301.     ' Get two vectors in the plane.
  302.     Nx = Point2.Coord(1) - Point1.Coord(1)
  303.     Ny = Point2.Coord(2) - Point1.Coord(2)
  304.     Nz = Point2.Coord(3) - Point1.Coord(3)
  305.     If Nx <> 0 Then
  306.         m3Cross v1x, v1y, v1z, Nx, Ny, Nz, 0, 1, 0
  307.     ElseIf Ny <> 0 Then
  308.         m3Cross v1x, v1y, v1z, Nx, Ny, Nz, 0, 0, 1
  309.     Else
  310.         m3Cross v1x, v1y, v1z, Nx, Ny, Nz, 1, 0, 0
  311.     End If
  312.     m3Cross v2x, v2y, v2z, Nx, Ny, Nz, v1x, v1y, v1z
  313.  
  314.     ' Normalize the vectors.
  315.     length = Sqr(v1x * v1x + v1y * v1y + v1z * v1z)
  316.     v1x = v1x / length
  317.     v1y = v1y / length
  318.     v1z = v1z / length
  319.  
  320.     length = Sqr(v2x * v2x + v2y * v2y + v2z * v2z)
  321.     v2x = v2x / length
  322.     v2y = v2y / length
  323.     v2z = v2z / length
  324.  
  325.     ' Make some rectangles.
  326.     For i = -WIRE_MAX To WIRE_MAX
  327.         For j = -WIRE_MAX To WIRE_MAX
  328.             WireFrame(i, j).Coord(1) = Point1.Coord(1) + i * WIRE_DX * v1x + j * WIRE_DX * v2x
  329.             WireFrame(i, j).Coord(2) = Point1.Coord(2) + i * WIRE_DX * v1y + j * WIRE_DX * v2y
  330.             WireFrame(i, j).Coord(3) = Point1.Coord(3) + i * WIRE_DX * v1z + j * WIRE_DX * v2z
  331.             WireFrame(i, j).Coord(4) = 1
  332.         Next j
  333.     Next i
  334. End Sub
  335. ' Apply a transformation matrix to the object.
  336. Public Sub RayTraceable_Apply(M() As Single)
  337. Dim i As Integer
  338. Dim j As Integer
  339.  
  340.     ' Transform the wire frame.
  341.     For i = -WIRE_MAX To WIRE_MAX
  342.         For j = -WIRE_MAX To WIRE_MAX
  343.             m3Apply WireFrame(i, j).Coord, _
  344.                  M, WireFrame(i, j).Trans
  345.         Next j
  346.     Next i
  347.  
  348.     ' Transform the plane's points.
  349.     m3Apply Point1.Coord, M, Point1.Trans
  350.     m3Apply Point2.Coord, M, Point2.Trans
  351. End Sub
  352. ' Apply a transformation matrix to the object.
  353. Public Sub RayTraceable_ApplyFull(M() As Single)
  354. Dim i As Integer
  355. Dim j As Integer
  356.  
  357.     ' Transform the wire frame.
  358.     For i = -WIRE_MAX To WIRE_MAX
  359.         For j = -WIRE_MAX To WIRE_MAX
  360.             m3ApplyFull WireFrame(i, j).Coord, _
  361.                      M, WireFrame(i, j).Trans
  362.         Next j
  363.     Next i
  364.  
  365.     ' Transform the plane's points.
  366.     m3ApplyFull Point1.Coord, M, Point1.Trans
  367.     m3ApplyFull Point2.Coord, M, Point2.Trans
  368. End Sub
  369.  
  370. ' Draw the object with backfaces removed.
  371. ' Draw the whole wire frame for planes.
  372. Public Sub RayTraceable_DrawBackfacesRemoved(ByVal pic As PictureBox)
  373.     RayTraceable_DrawWireFrame pic
  374. End Sub
  375. ' Return the red, green, and blue components of
  376. ' the surface at the hit position.
  377. Public Sub RayTraceable_FindHitColor(ByVal depth As Integer, Objects As Collection, ByVal eye_x As Single, ByVal eye_y As Single, ByVal eye_z As Single, ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByRef R As Integer, ByRef G As Integer, ByRef B As Integer)
  378. Dim Nx As Single
  379. Dim Ny As Single
  380. Dim Nz As Single
  381. Dim Vx As Single
  382. Dim Vy As Single
  383. Dim Vz As Single
  384. Dim NdotV As Single
  385.  
  386.     ' Find the unit normal at this point.
  387.     GetUnitNormal Nx, Ny, Nz
  388.  
  389.     ' Make sure the normal points towards the
  390.     ' center of projection.
  391.     Vx = EyeX - px
  392.     Vy = EyeY - py
  393.     Vz = EyeZ - pz
  394.     NdotV = Nx * Vx + Ny * Vy + Nz * Vz
  395.     If NdotV < 0 Then
  396.         Nx = -Nx
  397.         Ny = -Ny
  398.         Nz = -Nz
  399.     End If
  400.  
  401.     ' Get the hit color.
  402.     CalculateHitColor depth, Objects, Me, _
  403.         eye_x, eye_y, eye_z, _
  404.         px, py, pz, _
  405.         Nx, Ny, Nz, _
  406.         DiffuseKr, DiffuseKg, DiffuseKb, _
  407.         AmbientKr, AmbientKg, AmbientKb, _
  408.         SpecularK, SpecularN, _
  409.         ReflectedKr, ReflectedKg, ReflectedKb, IsReflective, _
  410.         TransmittedKr, TransmittedKg, TransmittedKb, TransN, n1, n2, IsTransparent, _
  411.         R, G, B
  412. End Sub
  413. ' See if the scanline plane with the indicated
  414. ' point and normal intersects this object.
  415. Public Sub RayTraceable_CullScanline(ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByVal Nx As Single, ByVal Ny As Single, ByVal Nz As Single)
  416.     ' Do not scanline cull planes.
  417.     DoneOnThisScanline = False
  418. End Sub
  419. ' Return the value T for the point of intersection
  420. ' between the vector from point (px, py, pz) in
  421. ' the direction <vx, vy, vz>.
  422. '
  423. ' direct_calculation is true if we are finding the
  424. ' intersection from a viewing position ray. It is
  425. ' false if we are finding an reflected intersection
  426. ' or a shadow feeler.
  427. Public Function RayTraceable_FindT(ByVal direct_calculation As Boolean, ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByVal Vx As Single, ByVal Vy As Single, ByVal Vz As Single) As Single
  428. Dim A As Single
  429. Dim B As Single
  430. Dim C As Single
  431. Dim D As Single
  432. Dim Nx As Single
  433. Dim Ny As Single
  434. Dim Nz As Single
  435. Dim denom As Single
  436. Dim t As Single
  437.  
  438.     ' Do not cull planes.
  439.  
  440.     ' Find the unit normal at this point.
  441.     GetUnitNormal Nx, Ny, Nz
  442.  
  443.     ' Compute the plane's parameters.
  444.     A = Nx
  445.     B = Ny
  446.     C = Nz
  447.     D = -(Nx * Point1.Trans(1) + _
  448.           Ny * Point1.Trans(2) + _
  449.           Nz * Point1.Trans(3))
  450.  
  451.     ' If the denominator = 0, the ray is parallel
  452.     ' to the plane so there's no intersection.
  453.     denom = A * Vx + B * Vy + C * Vz
  454.     If denom = 0 Then
  455.         RayTraceable_FindT = -1
  456.         Exit Function
  457.     End If
  458.  
  459.     ' Solve for t.
  460.     t = -(A * px + B * py + C * pz + D) / denom
  461.  
  462.     ' If there is no positive t value, there's no
  463.     ' intersection in this direction.
  464.     If t < 0.01 Then
  465.         RayTraceable_FindT = -1
  466.         Exit Function
  467.     End If
  468.  
  469.     ' We had a hit.
  470.     If direct_calculation Then HadHit = True
  471.  
  472.     RayTraceable_FindT = t
  473. End Function
  474. ' Return the minimum and maximum distances from
  475. ' this point.
  476. '
  477. ' Because planes extend infinitely, this is not
  478. ' terribly useful for this object. Instead return
  479. ' the point used to define the plane.
  480. Private Sub RayTraceable_GetRminRmax(new_min As Single, new_max As Single, ByVal X As Single, ByVal Y As Single, ByVal Z As Single)
  481. Dim dx As Single
  482. Dim dy As Single
  483. Dim dz As Single
  484. Dim dist As Single
  485.  
  486.     dx = X - Point1.Trans(1)
  487.     dy = Y - Point1.Trans(2)
  488.     dz = Z - Point1.Trans(3)
  489.     dist = Sqr(dx * dx + dy * dy + dz * dz)
  490.     new_max = dist
  491.     new_min = dist
  492. End Sub
  493.  
  494. ' Reset the ForeverCulled flag.
  495. Private Sub RayTraceable_ResetCulling()
  496.     ForeverCulled = False
  497.     HadHitOnPreviousScanline = False
  498. End Sub
  499.  
  500.  
  501.